package com.zjgsu.nftplatform.util;

import com.wechat.pay.contrib.apache.httpclient.WechatPayHttpClientBuilder;
import com.wechat.pay.contrib.apache.httpclient.auth.PrivateKeySigner;
import com.wechat.pay.contrib.apache.httpclient.auth.ScheduledUpdateCertificatesVerifier;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Credentials;
import com.wechat.pay.contrib.apache.httpclient.auth.WechatPay2Validator;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import org.apache.http.impl.client.CloseableHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Calendar;

/**
 * @author ahy231
 * @date 2021/12/1 15:38
 * @description
 */
@Component
public class PaymentUtil {

    static final int KEY_LENGTH_BYTE = 32;
    static final int TAG_LENGTH_BIT = 128;

    @Value("${wechat.api_v3_key}")
    private String apiV3Key;
    @Value("${wechat.mchid}")
    private String merchantId;
    @Value("${wechat.mchno}")
    private String merchantSerialNumber;
    @Value("${wechat.mchkeypath}")
    private String merchantPrivateKeyPath;

    // 循环产生商品id
    private static int index = 0;

    /**
     * 解密 ciphertext
     */
    public String decryptToString(byte[] associatedData, byte[] nonce, String ciphertext)
            throws GeneralSecurityException {
        try {
            Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");

            Assert.isTrue(apiV3Key.getBytes(StandardCharsets.UTF_8).length == KEY_LENGTH_BYTE,
                    "apiV3Key错误");
            SecretKeySpec key = new SecretKeySpec(apiV3Key.getBytes(StandardCharsets.UTF_8), "AES");
            GCMParameterSpec spec = new GCMParameterSpec(TAG_LENGTH_BIT, nonce);

            cipher.init(Cipher.DECRYPT_MODE, key, spec);
            cipher.updateAAD(associatedData);

            return new String(cipher.doFinal(Base64.getDecoder().decode(ciphertext)), StandardCharsets.UTF_8);
        } catch (NoSuchAlgorithmException | NoSuchPaddingException e) {
            throw new IllegalStateException(e);
        } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
            throw new IllegalArgumentException(e);
        }
    }

    /**
     * 获取商品订单号
     *
     * @param distributionId 分销商id
     */
    public String getOutTradeNo(int distributionId) {
        return "" + distributionId
                + "-" + new SimpleDateFormat("yyyyMMddHHmmss").format(Calendar.getInstance().getTime())
                + "-" + String.format("%04d", index = (index + 1) % 10000);
    }

    /**
     * 获取分销商id
     *
     * @param outTradeNo 商品id
     * @return 分销商id
     */
    public int getDistributionId(String outTradeNo) {
        return Integer.parseInt(outTradeNo.split("-")[0]);
    }

    /**
     * 支付加密请求client
     */
    public CloseableHttpClient getPayClient() {
        // 示例：私钥为String字符串
        PrivateKey merchantPrivateKey;
        try {
            merchantPrivateKey = PemUtil.loadPrivateKey(new FileInputStream(merchantPrivateKeyPath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return null;
        }

        // 使用定时更新的签名验证器，不需要传入证书
        ScheduledUpdateCertificatesVerifier verifier = new ScheduledUpdateCertificatesVerifier(
                new WechatPay2Credentials(merchantId, new PrivateKeySigner(merchantSerialNumber, merchantPrivateKey)),
                apiV3Key.getBytes(StandardCharsets.UTF_8));

        return WechatPayHttpClientBuilder.create()
                .withMerchant(merchantId, merchantSerialNumber, merchantPrivateKey)
                .withValidator((new WechatPay2Validator(verifier))).build();
    }

    /**
     * 签名
     * @param message 加密信息
     */
    public String sign(byte[] message) throws SignatureException, InvalidKeyException, NoSuchAlgorithmException, FileNotFoundException {
        PrivateKey privateKey = PemUtil.loadPrivateKey(new FileInputStream(merchantPrivateKeyPath));
        Signature sign = Signature.getInstance("SHA256withRSA");
        sign.initSign(privateKey);
        sign.update(message);

        return Base64.getEncoder().encodeToString(sign.sign());
    }
}
